package com.macro.mall.portal.service.impl;

import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.util.StrUtil;
import com.macro.mall.common.exception.Asserts;
import com.macro.mall.common.log.TrackExecutionTime;
import com.macro.mall.mapper.UmsMemberLevelMapper;
import com.macro.mall.mapper.UmsMemberMapper;
import com.macro.mall.model.UmsMember;
import com.macro.mall.model.UmsMemberExample;
import com.macro.mall.model.UmsMemberLevel;
import com.macro.mall.model.UmsMemberLevelExample;
import com.macro.mall.portal.domain.MemberDetails;
import com.macro.mall.portal.service.UmsMemberCacheService;
import com.macro.mall.portal.service.UmsMemberService;
import com.macro.mall.security.util.JwtTokenUtil;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

/** 会员管理Service实现类 Created by macro on 2018/8/3. */
@Service
public class UmsMemberServiceImpl implements UmsMemberService {
  private static final Logger LOGGER = LoggerFactory.getLogger(UmsMemberServiceImpl.class);
  @Autowired private PasswordEncoder passwordEncoder;
  @Autowired private JwtTokenUtil jwtTokenUtil;
  @Autowired private UmsMemberMapper memberMapper;
  @Autowired private UmsMemberLevelMapper memberLevelMapper;
  @Autowired private UmsMemberCacheService memberCacheService;

  @Value("${redis.key.authCode}")
  private String REDIS_KEY_PREFIX_AUTH_CODE;

  @Value("${redis.expire.authCode}")
  private Long AUTH_CODE_EXPIRE_SECONDS;

  @Override
  public UmsMember getByUsername(String username) {
    UmsMember member = memberCacheService.getMember(username);
    if (member != null) return member;
    UmsMemberExample example = new UmsMemberExample();
    example.createCriteria().andUsernameEqualTo(username);
    List<UmsMember> memberList = memberMapper.selectByExample(example);
    if (!CollectionUtils.isEmpty(memberList)) {
      member = memberList.get(0);
      memberCacheService.setMember(member);
      return member;
    }
    return null;
  }

  @Override
  public UmsMember getById(Long id) {
    return memberMapper.selectByPrimaryKey(id);
  }

  @Override
  public void register(String username, String password, String telephone, String authCode) {
    // 验证验证码
    if (!verifyAuthCode(authCode, telephone)) {
      Asserts.fail("验证码错误");
    }
    // 查询是否已有该用户
    UmsMemberExample example = new UmsMemberExample();
    example.createCriteria().andUsernameEqualTo(username);
    example.or(example.createCriteria().andPhoneEqualTo(telephone));
    List<UmsMember> umsMembers = memberMapper.selectByExample(example);
    if (!CollectionUtils.isEmpty(umsMembers)) {
      Asserts.fail("该用户已经存在");
    }
    // 没有该用户进行添加操作
    UmsMember umsMember = new UmsMember();
    umsMember.setUsername(username);
    umsMember.setPhone(telephone);
    umsMember.setPassword(passwordEncoder.encode(password));
    umsMember.setCreateTime(new Date());
    umsMember.setStatus(1);
    // 获取默认会员等级并设置
    UmsMemberLevelExample levelExample = new UmsMemberLevelExample();
    levelExample.createCriteria().andDefaultStatusEqualTo(1);
    List<UmsMemberLevel> memberLevelList = memberLevelMapper.selectByExample(levelExample);
    if (!CollectionUtils.isEmpty(memberLevelList)) {
      umsMember.setMemberLevelId(memberLevelList.get(0).getId());
    }
    memberMapper.insert(umsMember);
    umsMember.setPassword(null);
  }

  @Override
  public String generateAuthCode(String telephone) {
    StringBuilder sb = new StringBuilder();
    Random random = new Random();
    for (int i = 0; i < 6; i++) {
      sb.append(random.nextInt(10));
    }
    memberCacheService.setAuthCode(telephone, sb.toString());
    return sb.toString();
  }

  @Override
  public void updatePassword(String telephone, String password, String authCode) {
    UmsMemberExample example = new UmsMemberExample();
    example.createCriteria().andPhoneEqualTo(telephone);
    List<UmsMember> memberList = memberMapper.selectByExample(example);
    if (CollectionUtils.isEmpty(memberList)) {
      Asserts.fail("该账号不存在");
    }
    // 验证验证码
    if (!verifyAuthCode(authCode, telephone)) {
      Asserts.fail("验证码错误");
    }
    UmsMember umsMember = memberList.get(0);
    umsMember.setPassword(passwordEncoder.encode(password));
    memberMapper.updateByPrimaryKeySelective(umsMember);
    memberCacheService.delMember(umsMember.getId());
  }

  @Override
  public UmsMember getCurrentMember() {
    SecurityContext ctx = SecurityContextHolder.getContext();
    Authentication auth = ctx.getAuthentication();
    MemberDetails memberDetails = (MemberDetails) auth.getPrincipal();
    return memberDetails.getUmsMember();
  }

  @Override
  public void updateIntegration(Long id, Integer integration) {
    UmsMember record = new UmsMember();
    record.setId(id);
    record.setIntegration(integration);
    memberMapper.updateByPrimaryKeySelective(record);
    memberCacheService.delMember(id);
  }

  @Override
  public UserDetails loadUserByUsername(String username) {
    UmsMember member = getByUsername(username);
    if (member != null) {
      return new MemberDetails(member);
    }
    throw new UsernameNotFoundException("用户名或密码错误");
  }

  @Override
  public String login(String username, String password) {
    String token = null;
    // 密码需要客户端加密后传递
    try {
      UserDetails userDetails = loadUserByUsername(username);
      if (!passwordEncoder.matches(password, userDetails.getPassword())) {
        throw new BadCredentialsException("密码不正确");
      }
      UsernamePasswordAuthenticationToken authentication =
          new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
      SecurityContextHolder.getContext().setAuthentication(authentication);
      token = jwtTokenUtil.generateToken(userDetails);
    } catch (AuthenticationException e) {
      LOGGER.warn("登录异常:{}", e.getMessage());
    }
    return token;
  }

  @Override
  public String refreshToken(String token) {
    return jwtTokenUtil.refreshHeadToken(token);
  }

  // 对输入的验证码进行校验
  private boolean verifyAuthCode(String authCode, String telephone) {
    if (StrUtil.isEmpty(authCode)) {
      return false;
    }
    String realAuthCode = memberCacheService.getAuthCode(telephone);
    return authCode.equals(realAuthCode);
  }
}
